
package codeGenerate.json.converter;

import java.io.IOException;
import java.util.*;
import java.util.Map.Entry;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

import codeGenerate.common.utils.SystemUtils;
import codeGenerate.json.constants.JsonConstants;
import codeGenerate.json.vo.JavaClassVo;
import codeGenerate.json.vo.JavaFieldVo;
import codeGenerate.json.vo.JsonConfigVo;

/**
 * json转换器，将json字符串转换成类集合
 * @author fudewei
 */
public class JsonToClassConverter {

	private List<JavaClassVo> javaClassList = new ArrayList<>();

	private JsonConfigVo configVo;

	public JsonToClassConverter(JsonConfigVo configVo) {
		this.configVo = configVo;
	}

	public List<JavaClassVo> convert(String jsonStr) throws JsonProcessingException, IOException {
		ObjectMapper objectMapper = new ObjectMapper();
		JsonNode jn = objectMapper.readTree(jsonStr);
		recursionJson(jn, configVo.getBeanNamePrefix() + configVo.getBeanName());
		return javaClassList;
	}

	private void recursionJson(JsonNode parentJn, String customClassName) {
		//导入类
		Set<String> importList = new HashSet<>();
		//添加类列表
		JavaClassVo javaClass = new JavaClassVo();
		javaClass.setName(customClassName);
		javaClass.setImportList(importList);
		javaClassList.add(javaClass);
		//字段项
		List<JavaFieldVo> javaFieldList = new ArrayList<>();
		javaClass.setJavaFieldList(javaFieldList);
		// 循环整个json对象的键值对
		Iterator<Entry<String, JsonNode>> fields = parentJn.fields();
		while (fields.hasNext()) {
			Entry<String, JsonNode> entry = fields.next();
			String jsonFieldName = entry.getKey();
			JsonNode jn = entry.getValue();
			String className = configVo.getBeanNamePrefix() + SystemUtils.toClassName(jsonFieldName);
			JavaFieldVo javaField = new JavaFieldVo();
			javaField.setJsonFieldName(jsonFieldName);
			javaField.setClassFieldName(SystemUtils.toClassFieldName(jsonFieldName));
			if (jn.isObject()) {
				javaField.setJsonFieldType(JsonConstants.JSON_TYPE_OBJECT);
				javaField.setClassFieldType(className);
				javaField.setClassFieldTypePath(configVo.getPack() + "." + className);
				importList.add(javaField.getClassFieldTypePath());
				recursionJson(jn, className);
			} else if (jn.isArray()) {
				javaField.setJsonFieldType(JsonConstants.JSON_TYPE_ARRAY);
				importList.add(List.class.getName());
				if (jn.size() == 0) {
					System.out.println("警告：数组长度为0，不能确定数组里面的类型，默认使用Object，该字段名为：" + jsonFieldName);
					javaField.setClassFieldType("List<" + Object.class.getSimpleName() + ">");
					javaField.setClassFieldTypePath(Object.class.getName());
				} else {
					JsonNode childJe = jn.get(0);
					if (childJe.isObject()) {
						javaField.setClassFieldType("List<" + className + ">");
						javaField.setClassFieldTypePath(configVo.getPack() + "." + className);
						importList.add(javaField.getClassFieldTypePath());
						recursionJson(childJe, className);
					} else if (childJe.isArray()) {
						System.out.println("警告：数组里面不能包含数组，该字段名为：" + jsonFieldName);
					} else {
						Class<?> jsonType = getJsonType(childJe);
						javaField.setClassFieldType(jsonType.getSimpleName());
						javaField.setClassFieldTypePath(jsonType.getName());
					}

				}
			} else {
				//基本类型
				javaField.setJsonFieldValue(jn.asText());
				javaField.setJsonFieldType(JsonConstants.JSON_TYPE_BASE);
				Class<?> jsonType = getJsonType(jn);
				javaField.setClassFieldType(jsonType.getSimpleName());
				javaField.setClassFieldTypePath(jsonType.getName());
			}
			javaFieldList.add(javaField);
		}

	}

	private Class<?> getJsonType(JsonNode jn) {
		if (jn.isNull()) {
			System.out.println("warn：由于value为null值无法确定类型，默认生成String类型，建议改成实际值！");
			return String.class;
		}
		if (jn.isTextual()) {
			return String.class;
		}
		if (jn.isBoolean()) {
			return Boolean.class;
		}
		if (jn.isNumber()) {
			if (jn.isInt()) {
				return Integer.class;
			}
			if (jn.isLong()) {
				return Long.class;
			}
			if (jn.isFloat()) {
				return Float.class;
			}
			if (jn.isDouble()) {
				return Double.class;
			}
		}

		return String.class;
	}

}
